﻿#region Using

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

#endregion

namespace Vk.Methods.Polls
{
    /// <summary>
    ///     Опросы
    /// </summary>
    public class Polls
    {
        private readonly Api _api;

        public Polls(Api api)
        {
            _api = api;
        }

        /// <summary>
        ///     Отдает голос текущего пользователя за выбранный вариант ответа в указанном опросе.
        /// </summary>
        /// <param name="pollId">Идентификатор опроса, в котором необходимо проголосовать.</param>
        /// <param name="answerId">Идентификатор варианта ответа, за который необходимо проголосовать.</param>
        /// <param name="ownerId">
        ///     Идентификатор владельца опроса. Если параметр не указан, то он считается равным идентификатору
        ///     текущего пользователя.
        /// </param>
        /// <param name="isBoard">true – опрос находится в обсуждении, false – опрос прикреплен к стене</param>
        /// <returns>
        ///     В случае успеха возвращает:
        ///     true – если голос текущего пользователя был отдан за выбранный вариант ответа
        ///     false – если текущий пользователь уже голосовал в указанном опросе
        /// </returns>
        public async Task<bool> AddVote(int pollId, int answerId, int? ownerId = null, bool? isBoard = null)
        {
            var query = new ApiQuery("polls.addVote")
                .Add("poll_id", pollId)
                .Add("answer_id", answerId)
                .Add("owner_id", ownerId)
                .Add("is_board", isBoard);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Позволяет создавать опросы, которые впоследствии можно прикреплять к записям на странице пользователя или
        ///     сообщества
        /// </summary>
        /// <param name="question">Текст вопроса</param>
        /// <param name="addAnswers">
        ///     список вариантов ответов, например:
        ///     ["yes", "no", "maybe"]
        ///     Может быть не менее 1 и не более 10 вариантов ответа.
        ///     Данные в формате JSON
        /// </param>
        /// <param name="ownerId">
        ///     Если опрос будет добавлен в группу необходимо передать отрицательный идентификатор группы. По
        ///     умолчанию текущий пользователь.
        /// </param>
        /// <param name="isAnonymous">
        ///     true – анонимный опрос, список проголосовавших недоступен;
        ///     false – опрос публичный, список проголосовавших доступен;
        ///     По умолчанию – 0.
        /// </param>
        public async Task<Poll> Create(string question, string addAnswers, int? ownerId = null, bool? isAnonymous = null)
        {
            var query = new ApiQuery("polls.create")
                .Add("question", question)
                .Add("add_answers", addAnswers)
                .Add("owner_id", ownerId)
                .Add("is_anonymous", isAnonymous);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed ? new Poll(result) : null;
        }

        /// <summary>
        ///     Снимает голос текущего пользователя с выбранного варианта ответа в указанном опросе.
        /// </summary>
        /// <param name="ownerId">
        ///     Идентификатор владельца опроса. Если параметр не указан, то он считается равным идентификатору
        ///     текущего пользователя.
        /// </param>
        /// <param name="pollId">Идентификатор опроса, в котором необходимо снять голос.</param>
        /// <param name="answerId">Идентификатор варианта ответа, с которого необходимо снять голос.</param>
        /// <param name="isBoard">true – опрос находится в обсуждении, false – опрос прикреплен к стене</param>
        /// <returns>
        ///     В случае успеха возвращает:
        ///     true – если голос текущего пользователя был снят с выбранного варианта ответа
        ///     false – если текущий пользователь еще не голосовал в указанном опросе или указан не выбранный им вариант ответа
        /// </returns>
        public async Task<bool> DeleteVote(int pollId, int answerId, int? ownerId = null, bool? isBoard = null)
        {
            var query = new ApiQuery("polls.deleteVote")
                .Add("poll_id", pollId)
                .Add("answer_id", answerId)
                .Add("owner_id", ownerId)
                .Add("is_board", isBoard);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Позволяет редактировать созданные опросы
        /// </summary>
        /// <param name="pollId">Идентификатор редактируемого опроса </param>
        /// <param name="ownerId">Идентификатор владельца опроса </param>
        /// <param name="question">Новый текст редактируемого опроса </param>
        /// <param name="addAnswers">Список вариантов ответов</param>
        /// <param name="editAnswers">
        ///     Объект, содержащий варианты ответов, которые необходимо отредактировать;
        ///     ключ – идентификатор ответа, значение – новый текст ответа
        /// </param>
        /// <param name="deleteAnswers">Список идентификаторов ответов, которые необходимо удалить</param>
        /// <returns>В случае успешного выполнения - true</returns>
        public async Task<bool> Edit(int pollId,
                                     int ownerId,
                                     string question = null,
                                     string addAnswers = null,
                                     string deleteAnswers = null,
                                     string editAnswers = null)
        {
            var query = new ApiQuery("polls.edit")
                .Add("poll_id", pollId)
                .Add("owner_id", ownerId)
                .Add("question", question)
                .Add("add_answers", addAnswers)
                .Add("edit_answers", editAnswers)
                .Add("delete_answers", deleteAnswers);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed && result.Bool().Value;
        }

        /// <summary>
        ///     Возвращает детальную информацию об опросе по его идентификатору.
        /// </summary>
        /// <param name="pollId">Идентификатор опроса, информацию о котором необходимо получить.</param>
        /// <param name="ownerId">
        ///     Идентификатор владельца опроса, информацию о котором необходимо получить. Если параметр не
        ///     указан, то он считается равным идентификатору текущего пользователя.
        /// </param>
        /// <param name="isBoard">true – опрос находится в обсуждении, false – опрос прикреплен к стене</param>
        public async Task<Poll> GetById(int pollId, int? ownerId = null, bool? isBoard = null)
        {
            var query = new ApiQuery("polls.getById")
                .Add("poll_id", pollId)
                .Add("owner_id", ownerId)
                .Add("is_board", isBoard);

            var result = await _api.Manager.Execute(query);
            return _api.Manager.MethodSuccessed ? new Poll(result) : null;
        }

        /// <summary>
        ///     Получает список идентификаторов пользователей, которые выбрали определенные варианты ответа в опросе
        /// </summary>
        /// <param name="answerIds">Идентификаторы вариантов ответа</param>
        /// <param name="pollId">Идентификатор опроса</param>
        /// <param name="ownerId">Идентификатор пользователя или сообщества, которому принадлежит опрос</param>
        /// <param name="friendsOnly">
        ///     Указывает, необходимо ли возвращать только пользователей, которые являются друзьями текущего
        ///     пользователя
        /// </param>
        /// <param name="isBoard">true – опрос находится в обсуждении, false – опрос прикреплен к стене</param>
        /// <param name="offset">
        ///     Смещение относительно начала списка, для выборки определенного подмножества. Если параметр не
        ///     задан, то считается, что он равен 0.
        /// </param>
        /// <param name="count">
        ///     Количество возвращаемых идентификаторов пользователей.
        ///     Если параметр не задан, то считается, что он равен 100, если не задан параметр friends_only, в противном случае 10.
        ///     Максимальное значение параметра 1000, если не задан параметр friends_only, в противном случае 100.
        /// </param>
        /// <param name="fields">
        ///     Перечисленные через запятую поля анкет, необходимые для получения. Доступные значения: nickname,
        ///     screen_name, sex, bdate (birthdate), city, country, timezone, photo, photo_medium, photo_big, has_mobile, rate,
        ///     contacts, education, online, counters.
        /// </param>
        /// <param name="nameCase">
        ///     Падеж для склонения имени и фамилии пользователя. Возможные значения: именительный – nom,
        ///     родительный – gen, дательный – dat, винительный – acc, творительный – ins, предложный – abl. По умолчанию nom.
        /// </param>
        public async Task<List<AnswerUsers>> GetVoters(IEnumerable<int> answerIds,
                                                       int pollId,
                                                       int? ownerId = null,
                                                       bool? isBoard = null,
                                                       int? offset = null,
                                                       int? count = null,
                                                       IEnumerable<string> fields = null,
                                                       string nameCase = null,
                                                       bool? friendsOnly = null)
        {
            if (answerIds == null)
                throw new ArgumentNullException(nameof(answerIds));

            var query = new ApiQuery("polls.getVoters")
                .Add("poll_id", pollId)
                .Add("answer_ids", answerIds)
                .Add("owner_id", ownerId)
                .Add("is_board", isBoard)
                .Add("friends_only", friendsOnly)
                .Add("offset", offset)
                .Add("count", count)
                .Add("fields", fields)
                .Add("name_case", nameCase);

            var result = await _api.Manager.Execute(query);

            if (_api.Manager.MethodSuccessed)
            {
                var nodes = result.ChildNodes;
                if (nodes != null && nodes.Any())
                    return nodes.Select(x => new AnswerUsers(x)).ToList();
            }
            return null;
        }
    }
}